﻿using System;

namespace Glue.Internals
{
    internal static class TypeExtensions
    {
        public static String GetReadableName(this Type me)
        {
            if (NullableRuntimeType.IsNullable(me))
            {
                return new NullableRuntimeType(me).GetUnderlyingType().Name + "?";
            }
            if (me.IsGenericType)
            {
                var genericSignPosition = me.Name.IndexOf("`");
                if (genericSignPosition == -1) return me.Name;
                var name = me.Name.Substring(0, genericSignPosition);
                var arguments = me.GetGenericArguments();
                return name + "<" + String.Join(",", ToStringArray(arguments)) + ">";
            }

            return me.Name;
        }

        private static String[] ToStringArray(Type[] from)
        {
            var to = new String[from.Length];
            for (int i = 0; i < from.Length; i++)
            {
                to[i] = from[i].GetReadableName();
            }
            return to;
        }

        public static bool IsOfInterfaceType(this Type me,Type amIOfThisType)
        {
            if (me.IsGenericType)
            {
                return me.GetGenericTypeDefinition().Equals(amIOfThisType) 
                    || (amIOfThisType.IsInterface && me.GetInterface(amIOfThisType.Name, true) != null);
            }
            if (!me.IsGenericType)
            {
                return me.Equals(amIOfThisType) 
                    || (amIOfThisType.IsInterface && me.GetInterface(amIOfThisType.Name,true) != null);
            }
            return false;
        }

        public static object CreateInstance(this Type me)
        {
            return Activator.CreateInstance(me);
        }

        public static bool IsPrimitive(this Type type)
        {
            if (type.IsPrimitive) return true;
            if (type.IsEnum) return true;
            if (IsUnderlyingNullableTypePrimitive(type))
                return true;
            if (type.Equals(typeof(String))) return true;
            if (type.Equals(typeof(DateTime))) return true;
            if (type.Equals(typeof(TimeSpan))) return true;
            if (type.Equals(typeof(decimal))) return true;
            if (type.Equals(typeof(Guid))) return true;
            return false;
        }

        private static bool IsUnderlyingNullableTypePrimitive(Type type)
        {
            return NullableRuntimeType.IsNullable(type) && IsPrimitive(new NullableRuntimeType(type).GetUnderlyingType());
        }
    }
}
